home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 25 / Cream of the Crop 25.iso / bbs / doorinfo.zip / DOORUTIL.C < prev    next >
C/C++ Source or Header  |  1997-05-14  |  20KB  |  937 lines

  1. /*
  2. ** This set of functions is a 'standard' collection of I/O routines
  3. ** for Falken doors authors.
  4. **
  5. ** --------------------------------------------------------------------
  6. **
  7. ** Compile Options (MSC 5.1 and above)
  8. **   cl /AL /c /Gs doorutil.c
  9. **
  10. ** Compile and link a door program -
  11. **   cl /AL /c /Gs doorprog.c
  12. **   link doorprog doorutil lmtc;
  13. **
  14. **
  15. ** The purpose of these functions is to make the mechanics of
  16. ** interfacing with Falken as transparent as possible.
  17. **
  18. ** Each function is documented with a comment block preceeding
  19. ** the function.
  20. **
  21. ** The header file DOORUTIL.H contains function prototypes.
  22. **
  23. ** Global Variables -
  24. **
  25. ** Certain variables are defined in these routines, and have Global
  26. ** scope.  These variables are used by these functions, and may be
  27. ** used by your program, provided their values are not changed.
  28. **
  29. **  int     who;                which line the user is logged onto
  30. **  int     inq;                message queue for in-bound messages
  31. **  int     outq;               message queue for out-bound messages
  32. **  int     numlines;           number of lines on this Falken system
  33. **  acctp   *acct;              pointer to array of account structures
  34. **  userp   *user;              pointer to array of user structures
  35. **  struct  acct_rec *myacct;   pointer to THIS users account structure
  36. **  struct  user_rec *myuser;   pointer to THIS users user structure
  37. **  struct  msg3     m3;        initialization message structure
  38. **  struct  msg1    *m1;        general purpose message queue pointer
  39. **  char    workbuf[1300];      common area for message transfers
  40. */
  41.  
  42.  
  43. #include <stdio.h>
  44. #include <stdlib.h>
  45. #include <string.h>
  46. #include <stdarg.h>
  47.  
  48. #include <time.h>
  49. #include <dos.h>
  50. #include <ctype.h>
  51. #include "doorutil.h"        /* function prototypes */
  52. #include "c:\mt\tcb.h"
  53.  
  54. int isinstalled(void);
  55.  
  56. struct msg3 m3;
  57.  
  58. /*
  59. ** m1 is a pointer to a structure used for passing text between us
  60. ** and Falken
  61. */
  62.  
  63. struct msg1 *m1;
  64.  
  65. /*
  66. ** m4 is a pointer to a structure used by Falken to tell us how many
  67. ** bytes are available in the output buffer.
  68. */
  69.  
  70. struct msg4 *m4;
  71.  
  72. struct msg5 *m5;
  73.  
  74. struct msg6 *m6;
  75.  
  76. struct msg7 *m7;
  77.  
  78. /*
  79. ** cbr is a structure used when making database calls to Falken.
  80. ** Doors have the ability to manipulate Falkens databases, but
  81. ** must call Falken to do it.  This structure is set up for the
  82. ** database call, and then the address of this structure is passed
  83. ** to Falken in the mdbs structure below.
  84. */
  85.  
  86. struct call_bt_rec cbr;
  87.  
  88. struct mdbs_rec mdbs;
  89.  
  90. /*
  91. ** Workbuf is a character array used for intertask communications.
  92. ** All the structure pointers above (m1, m4), are loaded with
  93. ** the address of workbuf,making it a common memory region for
  94. ** intertask communication.
  95. */
  96.  
  97. unsigned char workbuf[1400];
  98.  
  99. int inq, outq, who, numlines;    /* see header comments above */
  100.  
  101. struct acct_rec far *acct;
  102. struct user_rec far *user;
  103.  
  104. struct cfg_rec far *cfg;    /* pointer to BBSCFG record */
  105.  
  106. /*
  107. ** acct and user are useful, giving us the address of the structure arrays.
  108. ** for simplified access, though, we will set up a pointer to OUR
  109. ** element in the array.
  110. **
  111. **   myacct->   will be the account record for the current user
  112. **   myuser->   will be the user record for the current user
  113. */
  114.  
  115. struct acct_rec far *myacct;
  116. struct user_rec far *myuser;
  117.  
  118. struct tcb_rec far *tcb;
  119.  
  120. int Mytcbnum;
  121.  
  122. message_out(int queue, void *b, int count)
  123. {
  124.     while (send_md_msg(queue, b, count) == -1)
  125.     {
  126.     delay(2);
  127.     }
  128. }
  129.  
  130. int a_exit(int code)
  131. {
  132.     exit(code);
  133. }
  134.  
  135. int check_tcb_names(char *name)
  136. {
  137.         int j;
  138.         for (j = 0; j < maxtasks; j++)
  139.         {
  140.                 if ((strcmp(tcb[j].tcbname, name) == 0) &&
  141.                         (tcb[j].cur_state != st_free))
  142.                 {
  143.                         break;
  144.                 }
  145.         }
  146.         if(j==maxtasks) return 0;
  147.         else return 1;
  148. }
  149.  
  150. int set_tcb_name(char *name)
  151. {
  152.         strcpy(tcb[Mytcbnum].tcbname, name);
  153. }
  154.  
  155.  
  156. int isinstalled()
  157. {
  158.     union REGS ir;
  159.  
  160.     ir.h.ah = 0x80;        /* test for cswitch installed. */
  161.     int86(0x21, &ir, &ir);
  162.     if (ir.x.ax == 0x1956)
  163.     return ir.x.bx;        /* it is installed, return version number */
  164.     return 0;
  165. }
  166.  
  167. int init()
  168. {
  169.     time_t t1;
  170.  
  171.     if (isinstalled() == 0)
  172.     {
  173.     puts("Falken BBS not running.");
  174.     a_exit(0);
  175.     }
  176.  
  177.     Mytcbnum = get_tcb_info(&tcb);
  178.  
  179.     get_tcb_address(&tcb);
  180.  
  181.     m1 = (struct msg1 *) workbuf;    /* set up the working buffer */
  182.     m4 = (struct msg4 *) workbuf;
  183.     m5 = (struct msg5 *) workbuf;
  184.     m6 = (struct msg6 *) workbuf;
  185.     m7 = (struct msg7 *) workbuf;
  186.  
  187.     m3.type = 0;
  188.     t1 = time(NULL) + 20L;
  189. /*
  190. ** Wait 20 seconds for the initialization message to come.
  191. ** This is gross overkill, since it will be here almost instantaniously
  192. ** if it is coming.
  193. */
  194.  
  195.     do
  196.     {
  197.     if (t1 < time(NULL))
  198.     {
  199.         a_exit(0);        /* waited too long for init message */
  200.     }
  201.     if (testmsg(1))
  202.     {
  203.         recvmsg(1, &m3, sizeof(struct msg3));
  204.         if (m3.type == 8)
  205.         a_exit(0);
  206.     }
  207.     relinq();        /* nothing to do for now... give up time
  208.                  * slice */
  209.     } while (m3.type != 7);
  210.  
  211. /*
  212. ** m3 is volatile.  It is a pointer to a block of memory that will be
  213. ** reused frequently.  Save the important information into our global
  214. ** variables.
  215. */
  216.  
  217.     who = m3.line;
  218.     inq = m3.inq;
  219.     outq = m3.outq;
  220.     numlines = m3.numlines;
  221.     user = m3.userptr;
  222.     acct = m3.acctptr;
  223.     cfg = m3.cfgptr;
  224.     myacct = &acct[who];
  225.     myuser = &user[who];
  226.     return who;            /* return the line number this user is on. */
  227. }
  228.  
  229. /*
  230. ** If something drastic has happened, and it is necessary to not only
  231. ** terminate the door, but to log this user off, call logoff().
  232. */
  233.  
  234. void logoff(int who)
  235. {
  236.     m1->type = 5;
  237.     m1->count = who;
  238.     message_out(0, workbuf, 4);
  239. }
  240.  
  241. /*
  242. ** setbinarymode() places the user's port into binary mode.
  243. ** it will then be up to the door to handle all I/O via FOSSIL calls.
  244. ** All of Falken's amenities, such as character echo, word wrap, input
  245. ** filtering, and all that will be gone.
  246. **
  247. ** This is useful for file transfer protocols, or for hot-key type
  248. ** menus.
  249. */
  250.  
  251. void setbinarymode(int who)
  252. {
  253.     m1->type = 8;
  254.     m1->count = who;
  255.     message_out(0, workbuf, 4);
  256. }
  257.  
  258. /*
  259. ** settextmode() returns the line to text mode, where the door must use
  260. ** message queues for communciation.
  261. ** The Falken I/O controls will become active again.
  262. */
  263.  
  264. void settextmode(int who)
  265. {
  266.     m1->type = 7;
  267.     m1->count = who;
  268.     message_out(0, workbuf, 4);
  269. }
  270.  
  271. /*
  272. ** clear_input_buffer() and clear_output_buffer() instruct Falken to
  273. ** remove all bytes from the input and output buffers, respectively,
  274. ** for this port.
  275. */
  276.  
  277. void clear_input_buffer(int who)
  278. {
  279.     m1->type = 13;
  280.     m1->count = who;
  281.     message_out(0, workbuf, 4);
  282. }
  283.  
  284. void clear_output_buffer(int who)
  285. {
  286.     m1->type = 14;
  287.     m1->count = who;
  288.     message_out(0, workbuf, 4);
  289. }
  290.  
  291. /*
  292. ** Do not use this call under normal circumstances.
  293. ** Use get_port() to gain control of ANOTHER serial port from Falken.
  294. ** This disables logins on that port.  This is used for the dial-out
  295. ** function.
  296. */
  297.  
  298. void get_port(int port)
  299. {
  300.     m1->type = 19;
  301.     m1->count = port;
  302.     message_out(0, workbuf, 4);
  303. }
  304.  
  305. /*
  306. ** Give the second port back to Falken with return_port().
  307. */
  308.  
  309. void return_port(int port)
  310. {
  311.     m1->type = 20;
  312.     m1->count = port;
  313.     message_out(0, workbuf, 4);
  314. }
  315.  
  316. /*
  317. ** get_oba() returns the number of bytes available in the user's
  318. ** output buffer.
  319. */
  320.  
  321. int get_oba()
  322. {
  323.     m4->type = 12;
  324.     message_out(outq, workbuf, 2);
  325.     do
  326.     {
  327.     recvmsg(inq, workbuf, sizeof(struct msg4));
  328.     if (m1->type == 8)
  329.         a_exit(0);
  330.     } while (m1->type != 6);
  331.     return m4->oba;
  332. }
  333.  
  334. /*
  335. ** get_in_cnt() returns the number of bytes waiting in the user's
  336. ** input buffer.  Falken will buffer the input until the user has
  337. ** pressed ENTER, at which time the entire buffer will be sent to
  338. ** the door on the message queue.
  339. */
  340.  
  341. int get_in_cnt()
  342. {
  343.     m1->type = 9;
  344.     message_out(outq, workbuf, 2);
  345.     do
  346.     {
  347.     recvmsg(inq, workbuf, sizeof(struct msg1));
  348.     if (m1->type == 8)
  349.         a_exit(0);
  350.     } while (m1->type != 5);
  351.     return m1->count;
  352. }
  353.  
  354. /*
  355. ** bbslog() sends a string to the Falken log file, and displays it on
  356. ** the Falken sysop screen.
  357. */
  358.  
  359. int bbslog(char *fs)
  360. {
  361.     int j;
  362.     strcpy(m1->text, fs);
  363.     m1->count = who;
  364.     m1->type = 18;
  365.     j = strlen(m1->text);
  366.     message_out(0, workbuf, j + 5);
  367.     relinq();            /* give the bbs a chance to log it */
  368.     return (j);
  369. }
  370.  
  371. /*
  372. ** lprintf does much the same thing, but it uses a format string
  373. ** ala printf().
  374. */
  375. void lprintf(char *fs,...)
  376. {
  377.     va_list argptr;
  378.     int j;
  379.     va_start(argptr, fs);
  380.     vsprintf(m1->text, fs, argptr);
  381.     va_end(argptr);
  382.     m1->count = who;
  383.     m1->type = 18;
  384.     j = strlen(m1->text);
  385.     message_out(0, workbuf, j + 5);
  386. }
  387.  
  388. /*
  389. ** qprintf() is just like printf(), except it sends the output to the
  390. ** users line instead of the local screen.
  391. */
  392.  
  393. int qprintf(char *fs,...)
  394. {
  395.     int j;
  396.     va_list argptr;
  397.     va_start(argptr, fs);
  398.     vsprintf(m1->text, fs, argptr);
  399.     va_end(argptr);
  400.     m1->count = who;
  401.     m1->type = 1;
  402.     j = strlen(m1->text);
  403.     message_out(0, workbuf, j + 5);
  404.     return (j);
  405. }
  406.  
  407. int qnprintf(int who, char *fs,...)
  408. {
  409.     int j;
  410.     va_list argptr;
  411.     va_start(argptr, fs);
  412.     vsprintf(m1->text, fs, argptr);
  413.     va_end(argptr);
  414.     m1->count = who;
  415.     m1->type = 1;
  416.     j = strlen(m1->text);
  417.     message_out(0, workbuf, j + 5);
  418.     return (j);
  419. }
  420.  
  421. /*
  422. ** qputs() sends a line of text to the user's line.  A newline is appended
  423. ** to the text, just like puts()
  424. */
  425.  
  426. int qputs(char *fs)
  427. {
  428.     int j;
  429.     strcpy(m1->text, fs);
  430.     strcat(m1->text, "\r");
  431.     m1->count = who;
  432.     m1->type = 1;
  433.     j = strlen(m1->text);
  434.     message_out(0, workbuf, j + 5);
  435.     return (j);
  436. }
  437.  
  438. /*
  439. ** send() is the same as qputs(), but does not append a newline to the
  440. ** text.
  441. */
  442.  
  443. int send(char *fs)
  444. {
  445.     int j;
  446.     int br_array[2];
  447.  
  448.     if ((j = strlen(fs)) > 1000)
  449.     {
  450.     br_array[0] = who;
  451.     br_array[1] = 0xff;
  452.     broadcast(fs, br_array);
  453.     }
  454.     else
  455.     {
  456.     strcpy(m1->text, fs);
  457.     m1->count = who;
  458.     m1->type = 1;
  459.     message_out(0, workbuf, j + 5);
  460.     }
  461.     return (j);
  462. }
  463.  
  464. int sendtoline(int w, char *fs)
  465. {
  466.     int j;
  467.     int br_array[2];
  468.  
  469.     if ((j = strlen(fs)) > 1000)
  470.     {
  471.     br_array[0] = w;
  472.     br_array[1] = 0xff;
  473.     broadcast(fs, br_array);
  474.     }
  475.     else
  476.     {
  477.     strcpy(m1->text, fs);
  478.     m1->count = w;
  479.     m1->type = 1;
  480.     message_out(0, workbuf, j + 5);
  481.     }
  482.     return (j);
  483. }
  484.  
  485. /*
  486. ** Broadcast means to send to multiple lines.
  487. ** The line numbers to receive the text are contained in an array
  488. ** of integers, terminated with an 0xff.
  489. */
  490.  
  491. void broadcast(char *fs, int *linenums)
  492. {
  493.     int flg;
  494.     int j;
  495.  
  496.     j = 0;
  497.     while ((j < numlines) && (linenums[j] != 0xff))
  498.     {
  499.     m5->sendto[j] = linenums[j];
  500.     j++;
  501.     }
  502.     m5->sendto[j] = 0xff;
  503.     m5->text = (char far *) fs;
  504.     m5->flag = (int far *) &flg;
  505.     m5->type = 33;
  506.     m5->tcbnum = Mytcbnum;
  507.     flg = 0;
  508.     message_out(0, m5, sizeof(struct msg5));
  509.     while (flg == 0)
  510.     relinq();
  511. }
  512.  
  513. void sendmsg(int who, int msgnum)
  514. {
  515.     m6->m6line = who;
  516.     m6->m6type = 29;
  517.     m6->m6msgnum = msgnum;
  518.     message_out(0, m6, sizeof(struct msg6));
  519. }
  520.  
  521. void getmsg(int ansiflag, int msgnum, char *fs)
  522. {
  523.     int flg;
  524.     m6->m6text = (char far *) fs;
  525.     m6->m6flag = (int far *) &flg;
  526.     m6->m6ansiflag = ansiflag;
  527.     m6->m6type = 30;
  528.     m6->m6msgnum = msgnum;
  529.     m6->m6tcbnum = Mytcbnum;
  530.     flg = 0;
  531.     message_out(0, m6, sizeof(struct msg6));
  532.     do
  533.     {
  534.     relinq();
  535.     } while (flg == 0);
  536. }
  537.  
  538. /*
  539. ** qgets() is the alternative to gets().  It reads a line of input from
  540. ** the user.  The line is truncated to 'len' bytes, and is nul-terminated.
  541. ** The number of bytes read is returned.
  542. */
  543.  
  544. int qgets(char *s, int len)
  545. {
  546.     do
  547.     {
  548.     recvmsg(inq, workbuf, sizeof(struct msg1));
  549.     if (m1->type == 8)
  550.         a_exit(0);
  551.     } while (m1->type != 1);
  552.     if (strlen(m1->text) > len)
  553.     {
  554.     m1->text[len] = '\0';    /* force truncation */
  555.     }
  556.     strcpy(s, m1->text);
  557.     return (strlen(s));
  558. }
  559.  
  560. /*
  561. ** tqgets() is the same as qgets(), plus a timeout value.  If no
  562. ** text is received before 'timeout' seconds pass, then an error is
  563. ** returned.
  564. */
  565.  
  566. int tqgets(char *s, int len, int timeout)
  567. {
  568.     time_t t1, t2;
  569.  
  570.     t1 = time(NULL);
  571.     t2 = t1 + (long) timeout;
  572.  
  573.     while (t1 < t2)
  574.     {
  575.     if (testmsg(inq))
  576.     {
  577.         recvmsg(inq, workbuf, sizeof(struct msg1));
  578.         if (m1->type == 8)
  579.         {
  580.         a_exit(0);
  581.         }
  582.         if (m1->type == 1)
  583.         {
  584.         if (strlen(m1->text) > len)
  585.         {
  586.             m1->text[len] = '\0';    /* force truncation */
  587.         }
  588.         strcpy(s, m1->text);
  589.         return strlen(s);
  590.         }
  591.     }
  592.     relinq();
  593.     t1 = time(NULL);
  594.     }
  595.     return -1;            /* return timeout error. */
  596. }
  597.  
  598. /*
  599. ** waitforempty() does just that.  It does not return to the caller
  600. ** until the user's output buffer is empty.
  601. */
  602.  
  603.  
  604. void waitforempty()
  605. {
  606.     while (get_oba() < 16384)
  607.     {
  608.     relinq();
  609.     }
  610. }
  611.  
  612. /*
  613. ** This function returns the serial number of the Falken system
  614. ** in use.
  615. */
  616.  
  617. int getserialnum(char *s)
  618. {
  619.     time_t t1;
  620.     m1->type = 15;        /* get Falken serial number */
  621.     message_out(outq, workbuf, 2);
  622.     t1 = time(NULL) + 10;    /* wait 5 seconds */
  623.     do
  624.     {
  625.     if (testmsg(inq))
  626.     {
  627.         recvmsg(inq, workbuf, 200);
  628.         if (m1->type == 8)
  629.         {
  630.         a_exit(0);
  631.         }
  632.     }
  633.     else if (time(NULL) > t1)
  634.     {
  635.         m1->type = 9;
  636.         m1->text[0] = '\0';
  637.     }
  638.     else
  639.     {
  640.         relinq();
  641.     }
  642.     } while (m1->type != 9);
  643.     strcpy(s, m1->text);
  644.     return strlen(s);
  645. }
  646.  
  647. /*
  648. ** This function returns the version number of the Falken system
  649. ** in use.
  650. */
  651.  
  652. int getversion(char *s)
  653. {
  654.     time_t t1;
  655.     m1->type = 25;        /* get Falken version number */
  656.     message_out(outq, workbuf, 2);
  657.     t1 = time(NULL) + 5;    /* wait 5 seconds */
  658.     do
  659.     {
  660.     if (testmsg(inq))
  661.     {
  662.         recvmsg(inq, workbuf, 200);
  663.         if (m1->type == 8)
  664.         {
  665.         a_exit(0);
  666.         }
  667.     }
  668.     else if (time(NULL) > t1)
  669.     {
  670.         m1->type = 11;
  671.         m1->text[0] = '\0';
  672.     }
  673.     else
  674.     {
  675.         relinq();
  676.     }
  677.     } while (m1->type != 11);
  678.     strcpy(s, m1->text);
  679.     return strlen(s);
  680. }
  681.  
  682.  
  683. /*
  684. ** BTRV is a routine to access database records from within a door.
  685. ** Paramaters are the same as calling BTRV normally, except the
  686. ** file ID is an integer, used to identify which file we want to
  687. ** access, rather than a pointer to an IX_DESC variable.
  688. **
  689. ** See the database documentation for more details, and when using
  690. ** this function to access the databases  ...  BE CAREFUL!
  691. */
  692.  
  693.  
  694. int btrv(int op, int file_id, void *addr, int *len, ENTRY * key, int keynum)
  695. {
  696.     int done;
  697.     cbr.bt_file_id = file_id;
  698.     cbr.data_addr = (void far *) addr;
  699.     cbr.length = (int far *) len;
  700.     cbr.data_key = (ENTRY far *) key;
  701.     cbr.keynumber = keynum;
  702.     cbr.bt_function = op;
  703.     mdbs.mdbs_type = 28;    /* new style database service */
  704.     mdbs.cbraddr = &cbr;
  705.     mdbs.tcbnum = Mytcbnum;
  706.     mdbs.doneflag = &done;
  707.     done = 0;
  708.     message_out(0, &mdbs, sizeof(struct mdbs_rec));
  709.     while (!done)
  710.     relinq();
  711.     return cbr.rtnvalue;
  712. }
  713.  
  714. /*
  715. ** Set the users page length to 'lines'.
  716. ** Lines = 0 to stop paging.  (the annoying 'Press ENTER to continue'.
  717. */
  718.  
  719. void btupag(int lines)
  720. {
  721.     m6->m6type = 31;
  722.     m6->m6line = who;
  723.     m6->m6msgnum = lines;
  724.     message_out(0, m6, sizeof(struct msg6));
  725. }
  726.  
  727. /*
  728. ** Tell Falken to monitor CD (non-0), or not monitor CD (0)
  729. ** on the given line.
  730. */
  731.  
  732. void setwatchdog(int lines, int value)
  733. {
  734.     if (value)
  735.     m6->m6type = 35;
  736.     else
  737.     m6->m6type = 36;
  738.     m6->m6line = who;
  739.     message_out(0, m6, sizeof(struct msg6));
  740. }
  741.  
  742. /*
  743. ** set echo,
  744. ** 0 = echo off, 1 = echo on, 2 = echo dots
  745. */
  746.  
  747. void btuech(int echoval)
  748. {
  749.     m6->m6type = 32;
  750.     m6->m6line = who;
  751.     m6->m6msgnum = echoval;
  752.     message_out(0, m6, sizeof(struct msg6));
  753. }
  754.  
  755. /*
  756. ** Reads an account record whose name or account number is in s1,
  757. ** load the account record into mem.
  758. */
  759.  
  760. int find_account(char *s1, void *mem)
  761. {
  762.     ENTRY acctkey;
  763.     int j;
  764.     char s[uidlen];
  765.  
  766.     strncpy(s, s1, uidlen - 1);
  767.     s[uidlen - 1] = '\0';    /* force a string at most uidlen-1 bytes */
  768.     strcpy(acctkey.key, s);    /* try account number */
  769.     j = sizeof(struct acct_rec);        /* just need to read a handle */
  770.     if (btrv(b_getequ, ACCT_NUM_FILE, mem, &j,
  771.          &acctkey, 0) == OK)
  772.     {                /* user id is in the account file */
  773.     strcpy(s, mem);        /* found an account number */
  774.     }
  775.     strcpy(acctkey.key, s);
  776.     j = sizeof(struct acct_rec);
  777.     return btrv(b_getequ, ACCT_FILE, mem, &j, &acctkey, 0);
  778. }
  779.  
  780. /*
  781. ** Start a door, and wait for it to finish, then return to the caller.
  782. */
  783.  
  784. int start_a_door(char *cmd, int pri)
  785. {
  786.     int j, k;
  787.     char old_name[10];
  788.  
  789.     j = load_a_door(cmd, pri);
  790.     if (j >= 0)
  791.     {
  792.     strcpy(old_name, myuser->doors_id);
  793.     for (k = 0; k < 9 && cmd[k] && cmd[k] != ' '; k++)
  794.     {
  795.         myuser->doors_id[k] = cmd[k];
  796.     }
  797.     myuser->doors_id[k] = '\0';
  798.     wait_for_door(j);
  799.     strcpy(myuser->doors_id, old_name);
  800.     }
  801.     return j;
  802. }
  803.  
  804. /*
  805. ** Wait until the tcb indicated returns to a free state
  806. ** meaning the task has terminated.
  807. */
  808.  
  809. void wait_for_door(int tcbnum)
  810. {
  811.     while (tcb[tcbnum].cur_state != st_free)
  812.     relinq();
  813. }
  814.  
  815. /*
  816. ** Load a door, returning a number < 0 if error.
  817. ** Returns the task number (TCB number) if successful
  818. */
  819.  
  820. int load_a_door(char *cmd, int pri)
  821. {
  822.     int j;
  823.     char junk[30];
  824.     char b[10];
  825.  
  826.     for (j = 0; j < 9 && cmd[j] && cmd[j] != ' '; j++)
  827.     {
  828.     b[j] = cmd[j];
  829.     }
  830.     b[j] = '\0';
  831.  
  832.     hog();
  833.     while (testmsg(1) != 0)
  834.     {
  835.     relinq();
  836.     }
  837.     message_out(1, &m3, sizeof(struct msg3));
  838.  
  839.     sprintf(junk, "Starting door : %s", b);
  840.     bbslog(junk);
  841.  
  842.     j = loadtask(cmd, pri, 1);
  843.     if (j == 1)
  844.     {
  845.     while ((j = get_load_status()) == 0)
  846.         relinq();
  847.     }
  848.     else
  849.     {
  850.     j = -1;
  851.     }
  852.     if (j < 0)
  853.     {
  854.     recvmsg(1, junk, 1);    /* pull the init event off. */
  855.     }
  856.     nohog();
  857.     return j;
  858. }
  859.  
  860. /*
  861. ** Save the user's account record to disk.
  862. */
  863.  
  864. void save_acct()
  865. {
  866.     m1->count = who;
  867.     m1->type = 22;
  868.     message_out(0, workbuf, 4);
  869. }
  870.  
  871. /*
  872. ** sendtoq() is the same as send(),
  873. ** but sends to a particular queue
  874. */
  875.  
  876. int sendtoq(char *fs, int qnum)
  877. {
  878.     int j;
  879.     j = strlen(fs);
  880.     strcpy(m1->text, fs);
  881.     m1->count = who;
  882.     m1->type = 1;
  883.     message_out(qnum, workbuf, j + 5);
  884.     return (j);
  885. }
  886.  
  887.  
  888. /*
  889. ** Find the user whose name matches the character string supplied.
  890. ** The character string may have data behind it (.sayto, etc),
  891. ** so do a limited compare based on the length of the user name.
  892. ** Choose the longest name, and only match if the text string
  893. ** supplied has a non-alphanumeric character where the name
  894. ** would end.
  895. */
  896.  
  897. int finduser(char *t, char **ptr)
  898. {
  899.     int i, j, k, l;
  900.     if (isdigit(*t))
  901.     {
  902.         k = atoi(t);
  903.         if ((k < 0) || (k >= numlines))
  904.             k = -1;
  905.         while (isdigit(*t))
  906.             t++;
  907.         while (isspace(*t))
  908.             t++;
  909.         *ptr = t;
  910.     }
  911.     else
  912.     {
  913.         for (i = l = 0; i < numlines; i++)
  914.         {
  915.             j = strlen(acct[i].acctname);
  916.             if ((user[i].u_stat != st_idle) && (!isalnum(t[j])) &&
  917.                 (strnicmp(t, acct[i].acctname, j) == 0) && (j > l))
  918.             {
  919.                 l = j;
  920.                 k = i;
  921.             }
  922.         }
  923.         if (l == 0)
  924.             k = -1;             /* didn't find a match */
  925.         else
  926.         {
  927.             t += strlen(acct[k].acctname);
  928.             while (isspace(*t))
  929.                 t++;
  930.             *ptr = t;
  931.         }
  932.     }
  933.     return k;
  934. }
  935.  
  936.  
  937.